package cn.xyy.log;

import cn.xyy.common.annotation.log.Log;
import cn.xyy.common.domain.mvc.R;
import cn.xyy.common.domain.system.auth.UserInfo;
import cn.xyy.common.domain.system.log.SysLog;
import cn.xyy.common.spring.SpringContextHolder;
import cn.xyy.common.spring.SpringMVCUtil;
import cn.xyy.common.utils.HttpUtils;
import cn.xyy.common.utils.LoggerUtil;
import cn.xyy.common.utils.StringUtils;
import cn.xyy.log.event.SysLogEvent;
import cn.xyy.web.AuthUserHolder;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

/**
 * 日志记录aop
 * 
 * @author xyy
 *
 */
@Order(7)
@Aspect
public class SysLogAspect {

	@Around("@annotation(log)")
	public Object method(ProceedingJoinPoint pjp, Log log) throws Throwable {

		SysLog sysLog = new SysLog();
		sysLog.setTimestamps(System.currentTimeMillis());
		sysLog.setCreateTime(new Date());
		sysLog.setStatus(1);

		// 方法执行后记录日志
		Object result = pjp.proceed();

		try {
			MethodSignature signature = (MethodSignature) pjp.getSignature();
			Method method = signature.getMethod();
			crateBLog(sysLog, method, pjp);
			sysLog.setTitle(log.value());
			sysLog.setDuration(System.currentTimeMillis() - sysLog.getTimestamps());
			sysLog.setResult(JSONObject.toJSONString(result));
			if (result == null || ((R) result).getCode() != R.CODE_200) {
				sysLog.setStatus(2);
			}
			// 将有OpertionBLog标记的日志记录到数据库
			SpringContextHolder.publishEvent(new SysLogEvent(sysLog));
		} catch (Exception e) {
			LoggerUtil.error(e.getMessage(), e);
		}

		return result;
	}

	private void crateBLog(SysLog sysLog, Method method, ProceedingJoinPoint pjp) {
		HttpServletRequest request = SpringMVCUtil.getRequest();
		sysLog.setUrl(request.getRequestURL().toString());
		sysLog.setIp(HttpUtils.getIpAddr(request));
		sysLog.setRequestmethod(request.getMethod());
		sysLog.setContentType(request.getContentType());
		sysLog.setRequestparams(getParameter(method, pjp.getArgs()));
		UserInfo user = AuthUserHolder.getUserInfo();
		if (user != null) {
			sysLog.setCreator(user.getUsername());
		}
	}

	/**
	 * 根据方法和传入的参数获取请求参数
	 */
	private String getParameter(Method method, Object[] args) {
		List<Object> argList = new ArrayList<>();
		Parameter[] parameters = method.getParameters();
		for (int i = 0; i < parameters.length; i++) {
			// 将RequestBody注解修饰的参数作为请求参数
			RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
			if (requestBody != null) {
				argList.add(args[i]);
			}
			// 将RequestParam注解修饰的参数作为请求参数
			RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
			if (requestParam != null) {
				Map<String, Object> map = new HashMap<>(4);
				String key = parameters[i].getName();
				if (!StringUtils.isEmpty(requestParam.value())) {
					key = requestParam.value();
				}
				map.put(key, args[i]);
				argList.add(map);
			}
		}
		if (argList.isEmpty()) {
			return "";
		}
		return argList.size() == 1 ? JSON.toJSONString(argList.get(0)) : JSON.toJSONString(argList);
	}
}
